package redis

import (
	"encoding/json"
	"fmt"
	"github.com/edgexfoundry/edgex-go/internal/app/models"
	"github.com/edgexfoundry/go-mod-core-contracts/v2/errors"
	"github.com/gomodule/redigo/redis"
)

const (
	ProductTransportCollection          = "md|pt"
	ProductTransportCollectionProductId = ProductTransportCollection + DBKeySeparator + "productid"
)

func productTransportStoreKey(id string) string {
	return CreateKey(ProductTransportCollection, id)
}

// 检查产品传输配置id是否存在
func productTransportIdExists(conn redis.Conn, id string) (bool, errors.EdgeX) {
	exists, err := objectIdExists(conn, productTransportStoreKey(id))
	if err != nil {
		return false, errors.NewCommonEdgeX(errors.KindDatabaseError, "product transport existence check by id failed", err)
	}
	return exists, nil
}

// productTransportById 通过id查询产品传输配置
func productTransportById(conn redis.Conn, id string) (productTransport models.ProductTransport, edgeXerr errors.EdgeX) {
	edgeXerr = getObjectById(conn, productTransportStoreKey(id), &productTransport)
	if edgeXerr != nil {
		return productTransport, errors.NewCommonEdgeXWrapper(edgeXerr)
	}
	return
}

// 向redis中存储产品传输配置
func sendAddProductTransportCmd(conn redis.Conn, storeKey string, pt models.ProductTransport) errors.EdgeX {
	dsJSONBytes, err := json.Marshal(pt)
	if err != nil {
		return errors.NewCommonEdgeX(errors.KindContractInvalid, "unable to JSON marshal product transport for Redis persistence", err)
	}
	// md|pt:产品传输配置id    键类型：string
	_ = conn.Send(SET, storeKey, dsJSONBytes)
	// md|pt:productid:产品id 键类型：有序数组
	_ = conn.Send(ZADD, CreateKey(ProductTransportCollectionProductId, pt.ProductId), 0, storeKey)
	return nil
}

// 从redis中删除产品传输配置
func sendDeleteProductTransportCmd(conn redis.Conn, storeKey string, pt models.ProductTransport) errors.EdgeX {
	// md|pt:产品传输配置id    键类型：string
	_ = conn.Send(DEL, storeKey)
	// md|pt:productid:产品id 键类型：有序数组
	_ = conn.Send(ZREM, CreateKey(ProductTransportCollectionProductId, pt.ProductId), storeKey)
	return nil
}

// 添加产品传输配置
func addProductTransport(conn redis.Conn, pt models.ProductTransport) (models.ProductTransport, errors.EdgeX) {
	// 检查产品传输配置id是否存在
	exists, edgeXerr := productTransportIdExists(conn, pt.Id)
	if edgeXerr != nil {
		return pt, errors.NewCommonEdgeXWrapper(edgeXerr)
	} else if exists {
		return pt, errors.NewCommonEdgeX(errors.KindDuplicateName, fmt.Sprintf("product transport id %s already exists", pt.Id), edgeXerr)
	}

	transportStoreKey := productTransportStoreKey(pt.Id)
	// 事务开始
	_ = conn.Send(MULTI)
	edgeXerr = sendAddProductTransportCmd(conn, transportStoreKey, pt)
	if edgeXerr != nil {
		return pt, errors.NewCommonEdgeXWrapper(edgeXerr)
	}
	// 事务结束
	_, err := conn.Do(EXEC)
	if err != nil {
		errors.NewCommonEdgeX(errors.KindDatabaseError, "product transport failed", err)
	}
	return pt, edgeXerr
}

// 根据产品id分页查询产品传输配置
func AllTransportsByProductId(conn redis.Conn, offset int, limit int, productId string) (productTransports []models.ProductTransport, edgeXerr errors.EdgeX) {
	// 分页查询产品传输配置
	objects, edgeXerr := getObjectsByRange(conn, CreateKey(ProductTransportCollectionProductId, productId), offset, limit)
	if edgeXerr != nil {
		return productTransports, errors.NewCommonEdgeXWrapper(edgeXerr)
	}
	// 将返回值转换为产品传输配置数组
	productTransports = make([]models.ProductTransport, len(objects))
	for i, v := range objects {
		pt := models.ProductTransport{}
		err := json.Unmarshal(v, &pt)
		if err != nil {
			continue
		}
		productTransports[i] = pt
	}
	return productTransports, nil
}

// 批量删除产品传输配置
func ProductTransportDelete(conn redis.Conn, productTransportIds []string) errors.EdgeX {
	var productTransports []models.ProductTransport
	for _, id := range productTransportIds {
		// 通过id查询产品传输配置
		transport, err := productTransportById(conn, id)
		if err != nil {
			return errors.NewCommonEdgeXWrapper(err)
		}
		productTransports = append(productTransports, transport)
	}
	// 事务开始
	_ = conn.Send(MULTI)
	for i, id := range productTransportIds {
		storeKey := productTransportStoreKey(id)
		err := sendDeleteProductTransportCmd(conn, storeKey, productTransports[i])
		if err != nil {
			return errors.NewCommonEdgeXWrapper(err)
		}
	}
	// 事务结束
	_, err := conn.Do(EXEC)
	if err != nil {
		return errors.NewCommonEdgeX(errors.KindDatabaseError, "product transport delete failed", err)
	}
	return nil
}

// 更新产品传输配置
func UpdateProductTransport(conn redis.Conn, pt models.ProductTransport) errors.EdgeX {
	// 通过id查询原产品传输配置
	oldTransport, err := productTransportById(conn, pt.Id)
	if err != nil {
		return errors.NewCommonEdgeXWrapper(err)
	}

	// 事务开始
	_ = conn.Send(MULTI)
	storeKey := productTransportStoreKey(pt.Id)
	sendDeleteProductTransportCmd(conn, storeKey, oldTransport)
	err = sendAddProductTransportCmd(conn, storeKey, pt)
	if err != nil {
		return errors.NewCommonEdgeXWrapper(err)
	}
	// 事务结束
	_, err2 := conn.Do(EXEC)
	if err2 != nil {
		return errors.NewCommonEdgeXWrapper(err2)
	}
	return nil
}
